package com.insight.export.generator;

import com.insight.common.enums.ExportFormat;
import com.insight.entity.DataSource;
import com.insight.entity.MetadataTable;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * T087: HTML格式数据字典生成器
 * <p>
 * 生成符合HTML5规范的数据字典文档,包含样式和语义化标签.
 * 包含数据源信息、表目录、表详情(列/索引)等完整信息.
 * </p>
 *
 * <p><b>生成的文档结构</b>:</p>
 * <pre>
 * &lt;!DOCTYPE html&gt;
 * &lt;html&gt;
 *   &lt;head&gt;
 *     &lt;meta charset="UTF-8"&gt;
 *     &lt;title&gt;数据字典&lt;/title&gt;
 *     &lt;style&gt;...&lt;/style&gt;
 *   &lt;/head&gt;
 *   &lt;body&gt;
 *     &lt;h1&gt;数据字典&lt;/h1&gt;
 *     &lt;section&gt;数据源信息&lt;/section&gt;
 *     &lt;section&gt;表目录&lt;/section&gt;
 *     &lt;section&gt;表详情&lt;/section&gt;
 *   &lt;/body&gt;
 * &lt;/html&gt;
 * </pre>
 *
 * @author Insight Team
 */
public class HtmlExportGenerator implements ExportGenerator {

    private static final DateTimeFormatter TIMESTAMP_FORMAT =
            DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss");
    private static final DateTimeFormatter DISPLAY_FORMAT =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    public Path generate(DataSource dataSource, List<MetadataTable> tables, Path outputDir)
            throws IOException {
        // 参数验证
        validateParameters(dataSource, tables, outputDir);

        // 确保输出目录存在
        if (!Files.exists(outputDir)) {
            Files.createDirectories(outputDir);
        }

        // 生成文件名: datasource_timestamp.html
        String timestamp = LocalDateTime.now().format(TIMESTAMP_FORMAT);
        String fileName = String.format("%s_%s.html", sanitizeFileName(dataSource.getName()), timestamp);
        Path outputFile = outputDir.resolve(fileName);

        // 生成HTML内容
        StringBuilder html = new StringBuilder();
        appendDoctype(html);
        appendHtmlHead(html, dataSource);
        appendBodyStart(html);
        appendHeader(html, dataSource);
        appendDataSourceInfo(html, dataSource);
        appendTableOfContents(html, tables);
        appendTableDetails(html, tables);
        appendBodyEnd(html);

        // 写入文件
        Files.writeString(outputFile, html.toString());

        return outputFile;
    }

    @Override
    public ExportFormat getSupportedFormat() {
        return ExportFormat.HTML;
    }

    @Override
    public String getFileExtension() {
        return "html";
    }

    /**
     * 验证参数
     */
    private void validateParameters(DataSource dataSource, List<MetadataTable> tables, Path outputDir) {
        if (dataSource == null) {
            throw new IllegalArgumentException("数据源不能为null");
        }
        if (tables == null) {
            throw new IllegalArgumentException("表列表不能为null");
        }
        if (outputDir == null) {
            throw new IllegalArgumentException("输出目录不能为null");
        }
    }

    /**
     * 追加DOCTYPE声明
     */
    private void appendDoctype(StringBuilder sb) {
        sb.append("<!DOCTYPE html>\n");
        sb.append("<html lang=\"zh-CN\">\n");
    }

    /**
     * 追加HTML head部分
     */
    private void appendHtmlHead(StringBuilder sb, DataSource dataSource) {
        sb.append("<head>\n");
        sb.append("    <meta charset=\"UTF-8\">\n");
        sb.append("    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n");
        sb.append(String.format("    <title>数据字典 - %s</title>\n", escape(dataSource.getName())));
        appendStyles(sb);
        sb.append("</head>\n");
    }

    /**
     * 追加CSS样式
     */
    private void appendStyles(StringBuilder sb) {
        sb.append("    <style>\n");
        sb.append("        * { margin: 0; padding: 0; box-sizing: border-box; }\n");
        sb.append("        body { font-family: 'Segoe UI', Arial, sans-serif; line-height: 1.6; padding: 20px; background: #f5f5f5; }\n");
        sb.append("        .container { max-width: 1200px; margin: 0 auto; background: white; padding: 30px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }\n");
        sb.append("        h1 { color: #333; border-bottom: 3px solid #007bff; padding-bottom: 10px; margin-bottom: 20px; }\n");
        sb.append("        h2 { color: #555; margin-top: 30px; margin-bottom: 15px; border-left: 4px solid #007bff; padding-left: 10px; }\n");
        sb.append("        h3 { color: #666; margin-top: 20px; margin-bottom: 10px; }\n");
        sb.append("        .meta-info { background: #f8f9fa; padding: 15px; border-radius: 4px; margin-bottom: 20px; }\n");
        sb.append("        .meta-info p { margin: 5px 0; }\n");
        sb.append("        table { width: 100%; border-collapse: collapse; margin: 15px 0; background: white; }\n");
        sb.append("        th, td { padding: 12px; text-align: left; border: 1px solid #ddd; }\n");
        sb.append("        th { background: #007bff; color: white; font-weight: 600; }\n");
        sb.append("        tr:nth-child(even) { background: #f8f9fa; }\n");
        sb.append("        tr:hover { background: #e9ecef; }\n");
        sb.append("        .table-card { background: white; padding: 20px; margin: 20px 0; border-radius: 4px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n");
        sb.append("        .empty-message { text-align: center; color: #999; padding: 40px; font-style: italic; }\n");
        sb.append("        .timestamp { color: #666; font-size: 0.9em; margin-top: 30px; text-align: center; }\n");
        sb.append("    </style>\n");
    }

    /**
     * 追加body开始标签
     */
    private void appendBodyStart(StringBuilder sb) {
        sb.append("<body>\n");
        sb.append("    <div class=\"container\">\n");
    }

    /**
     * 追加body结束标签
     */
    private void appendBodyEnd(StringBuilder sb) {
        sb.append("        <div class=\"timestamp\">生成时间: ");
        sb.append(LocalDateTime.now().format(DISPLAY_FORMAT));
        sb.append("</div>\n");
        sb.append("    </div>\n");
        sb.append("</body>\n");
        sb.append("</html>\n");
    }

    /**
     * 追加文档头部
     */
    private void appendHeader(StringBuilder sb, DataSource dataSource) {
        sb.append("        <h1>数据字典</h1>\n");
        sb.append("        <div class=\"meta-info\">\n");
        sb.append(String.format("            <p><strong>数据源:</strong> %s</p>\n",
                escape(dataSource.getName())));
        sb.append(String.format("            <p><strong>数据库类型:</strong> %s</p>\n",
                dataSource.getDbType()));
        sb.append("        </div>\n");
    }

    /**
     * 追加数据源信息章节
     */
    private void appendDataSourceInfo(StringBuilder sb, DataSource dataSource) {
        sb.append("        <h2>数据源信息</h2>\n");
        sb.append("        <table>\n");
        sb.append("            <thead>\n");
        sb.append("                <tr><th>项目</th><th>值</th></tr>\n");
        sb.append("            </thead>\n");
        sb.append("            <tbody>\n");
        sb.append(String.format("                <tr><td>数据源名称</td><td>%s</td></tr>\n",
                escape(dataSource.getName())));
        sb.append(String.format("                <tr><td>数据库类型</td><td>%s</td></tr>\n",
                dataSource.getDbType()));
        sb.append(String.format("                <tr><td>主机地址</td><td>%s:%d</td></tr>\n",
                dataSource.getHost(), dataSource.getPort()));
        sb.append(String.format("                <tr><td>数据库名</td><td>%s</td></tr>\n",
                dataSource.getDatabaseName() != null ? escape(dataSource.getDatabaseName()) : "N/A"));
        sb.append(String.format("                <tr><td>用户名</td><td>%s</td></tr>\n",
                escape(dataSource.getUsername())));
        sb.append("            </tbody>\n");
        sb.append("        </table>\n");
    }

    /**
     * 追加表目录章节
     */
    private void appendTableOfContents(StringBuilder sb, List<MetadataTable> tables) {
        sb.append("        <h2>表目录</h2>\n");

        if (tables.isEmpty()) {
            sb.append("        <div class=\"empty-message\">暂无表信息</div>\n");
            return;
        }

        sb.append("        <table>\n");
        sb.append("            <thead>\n");
        sb.append("                <tr><th>表名</th><th>注释</th><th>行数</th><th>数据大小</th></tr>\n");
        sb.append("            </thead>\n");
        sb.append("            <tbody>\n");

        for (MetadataTable table : tables) {
            sb.append("                <tr>\n");
            sb.append(String.format("                    <td>%s</td>\n",
                    escape(table.getTableName())));
            sb.append(String.format("                    <td>%s</td>\n",
                    escape(table.getTableComment() != null ? table.getTableComment() : "")));
            sb.append(String.format("                    <td>%,d</td>\n",
                    table.getRowCount() != null ? table.getRowCount() : 0));
            sb.append(String.format("                    <td>%s</td>\n",
                    formatBytes(0L /* getDataLength removed */)));
            sb.append("                </tr>\n");
        }

        sb.append("            </tbody>\n");
        sb.append("        </table>\n");
    }

    /**
     * 追加表详情章节
     */
    private void appendTableDetails(StringBuilder sb, List<MetadataTable> tables) {
        sb.append("        <h2>表详情</h2>\n");

        for (MetadataTable table : tables) {
            appendTableDetail(sb, table);
        }
    }

    /**
     * 追加单个表的详细信息
     */
    private void appendTableDetail(StringBuilder sb, MetadataTable table) {
        sb.append("        <div class=\"table-card\">\n");

        // 表名和注释
        sb.append(String.format("            <h3>%s</h3>\n",
                escape(table.getTableName())));
        if (table.getTableComment() != null && !table.getTableComment().isEmpty()) {
            sb.append(String.format("            <p><em>%s</em></p>\n",
                    escape(table.getTableComment())));
        }

        // 表统计信息
        sb.append("            <h4>基本信息</h4>\n");
        sb.append("            <table>\n");
        sb.append("                <thead>\n");
        sb.append("                    <tr><th>项目</th><th>值</th></tr>\n");
        sb.append("                </thead>\n");
        sb.append("                <tbody>\n");
        sb.append(String.format("                    <tr><td>模式</td><td>%s</td></tr>\n",
                escape(table.getTableSchema() != null ? table.getTableSchema() : "N/A")));
        sb.append(String.format("                    <tr><td>表类型</td><td>%s</td></tr>\n",
                escape(table.getTableType() != null ? table.getTableType() : "TABLE")));
        sb.append(String.format("                    <tr><td>行数</td><td>%,d</td></tr>\n",
                table.getRowCount() != null ? table.getRowCount() : 0));
        sb.append(String.format("                    <tr><td>数据大小</td><td>%s</td></tr>\n",
                formatBytes(0L /* getDataLength removed */)));
        sb.append(String.format("                    <tr><td>索引大小</td><td>%s</td></tr>\n",
                formatBytes(0L /* getIndexLength removed */)));
        sb.append("                </tbody>\n");
        sb.append("            </table>\n");

        // 注意: 列和索引信息需要通过Repository查询获取,当前版本暂时省略
        // TODO: 在Service层实现时,需要预加载列和索引信息

        sb.append("        </div>\n");
    }

    /**
     * 格式化字节数为可读格式
     */
    private String formatBytes(Long bytes) {
        if (bytes == null || bytes == 0) {
            return "0 B";
        }
        if (bytes < 1024) {
            return bytes + " B";
        }
        if (bytes < 1024 * 1024) {
            return String.format("%.2f KB", bytes / 1024.0);
        }
        if (bytes < 1024L * 1024 * 1024) {
            return String.format("%.2f MB", bytes / (1024.0 * 1024));
        }
        return String.format("%.2f GB", bytes / (1024.0 * 1024 * 1024));
    }

    /**
     * 转义HTML特殊字符
     */
    private String escape(String text) {
        if (text == null) {
            return "";
        }
        return text.replace("&", "&amp;")
                .replace("<", "&lt;")
                .replace(">", "&gt;")
                .replace("\"", "&quot;")
                .replace("'", "&#39;");
    }

    /**
     * 清理文件名中的非法字符
     */
    private String sanitizeFileName(String fileName) {
        if (fileName == null) {
            return "export";
        }
        // 移除Windows文件名非法字符: < > : " / \ | ? *
        return fileName.replaceAll("[<>:\"/\\\\|?*]", "_");
    }
}
